package com.atung.parking.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atung.parking.config.auth.PwdCreateUtil;
import com.atung.parking.config.auth.entity.AuthUserEntity;
import com.atung.parking.config.result.ApiResult;
import com.atung.parking.config.security.JwtTokenUtil;
import com.atung.parking.config.utils.WxUrlTool;
import com.atung.parking.dto.WxLoginDTO;
import com.atung.parking.entity.BusSuperUser;
import com.atung.parking.entity.BusUser;
import com.atung.parking.enums.AdminType;
import com.atung.parking.enums.SuperUserState;
import com.atung.parking.mapper.BusSuperUserMapper;
import com.atung.parking.mapper.BusUserMapper;
import com.atung.parking.request.AdminAuthLoginRequest;
import com.atung.parking.request.WxLoginRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.log4j.Log4j2;
import lombok.val;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
 * @author Administrator
 */
@Service
@Log4j2
public class AuthServiceImpl {
    @Resource
    private BusSuperUserMapper busSuperUserMapper;
    @Resource
    private BusUserMapper busUserMapper;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.secret}")
    private String secret;

    public ApiResult administratorLoginService(AdminAuthLoginRequest adminAuthLoginRequest, HttpServletRequest servletRequest) {
        QueryWrapper<BusSuperUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", adminAuthLoginRequest.getUserName());
        BusSuperUser busSuperUser = busSuperUserMapper.selectOne(queryWrapper);
        if (Objects.isNull(busSuperUser)) {
            return ApiResult.noLoginName();
        }
        //判断用户状态
        if (busSuperUser.getStatus().equals(SuperUserState.DISABLED.ordinal())) {
            return ApiResult.userStateErr();
        }
        adminAuthLoginRequest
                .setPassword(PwdCreateUtil.createPwd(adminAuthLoginRequest.getPassword(),
                        busSuperUser.getSalt()));
        //判断用户密码
        if (!adminAuthLoginRequest.getPassword().equals(busSuperUser.getPassword())) {
            return ApiResult.pwdLoginErr();
        }
        //封装用户信息
        AuthUserEntity authUserEntity = new AuthUserEntity();
        authUserEntity.setUserId(busSuperUser.getId());
        authUserEntity.setUsername(busSuperUser.getUsername());
        authUserEntity.setRoleType(AdminType.fromCode(busSuperUser.getType()));
        authUserEntity.setName(authUserEntity.getName());
        authUserEntity.setPhone(authUserEntity.getPhone());
        authUserEntity.setPhoto("https://img1.baidu.com/it/u=366724989,267422008&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800");
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(authUserEntity, null, authUserEntity.getAuthorities());
        //安全框架封装用户认证信息
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        //返回token
        String token = jwtTokenUtil.generateToken(authUserEntity, servletRequest);
        return ApiResult.ok(token);

    }

    public ApiResult wxLoginService(WxLoginRequest wxLoginRequest, HttpServletRequest servletRequest) {
        String url = (WxUrlTool
                .GetWxLoginUrl.replace("APPID", appid).replace("SECTET", secret).replace("JSCODE", wxLoginRequest.getCode()));
        String response = HttpUtil.get(url);

        WxLoginDTO loginMessage = JSONUtil.toBean(response, WxLoginDTO.class);
        if (Objects.nonNull(loginMessage.getErrcode())) {
            return ApiResult.fail(loginMessage.getErrcode(), loginMessage.getErrmsg());
        }
        //获取头像  用户名

        JSONObject userInfo = getUserInfo(wxLoginRequest.getEncryptedData(), loginMessage.getSession_key(), wxLoginRequest.getIv());
        String wxName = "微信用户";
        String wxPhoto = "";
        String phoneNumber = "";
        if (Objects.nonNull(userInfo)) {
            wxName = Optional.ofNullable(userInfo.getString("nickName")).orElse("微信用户");
            wxPhoto = Optional.ofNullable(userInfo.getString("avatarUrl")).orElse("");
            phoneNumber = Optional.ofNullable(userInfo.getString("phoneNumber")).orElse("");
        }
        String openid = loginMessage.getOpenid();

        QueryWrapper<BusUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("open_id", openid);
        BusUser busUser = busUserMapper.selectOne(queryWrapper);
        //用户编号
        AuthUserEntity authUserEntity = new AuthUserEntity();
        if (Objects.isNull(busUser)) {
            BusUser busUser1 = new BusUser();
            busUser1.setOpenId(openid);
            busUser1.setWxName(wxName);
            busUser1.setWxPhoto(wxPhoto);
            busUser1.setPhone(phoneNumber);
            busUser1.setCreatorTime(String.valueOf(Instant.now().toEpochMilli()));
            busUser1.setCreatorName(wxName);
            busUser1.setStatus(0);
            Integer insert = busUserMapper.insert(busUser1);
            if (insert == 0) {
                return ApiResult.fail(loginMessage.getErrcode(), loginMessage.getErrmsg());
            }
            authUserEntity.setUserId(busUser1.getId());
            authUserEntity.setUsername(wxName);
            authUserEntity.setRoleType(AdminType.USER);
            authUserEntity.setName(wxName);
            authUserEntity.setPhone(authUserEntity.getPhone());
            authUserEntity.setPhoto(wxPhoto);
        } else {
            busUser.setWxName(wxName);
            busUser.setWxPhoto(wxPhoto);
            busUser.setPhone(phoneNumber);
            busUser.setModifierTime(String.valueOf(Instant.now().toEpochMilli()));
            busUserMapper.updateById(busUser);
            authUserEntity.setUserId(busUser.getId());
            authUserEntity.setUsername(wxName);
            authUserEntity.setRoleType(AdminType.USER);
            authUserEntity.setName(wxName);
            authUserEntity.setPhone(busUser.getPhone());
            authUserEntity.setPhoto(wxPhoto);

        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(authUserEntity, null, authUserEntity.getAuthorities());

        //安全框架封装用户认证信息
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        String token = jwtTokenUtil.generateToken(authUserEntity, servletRequest);
        return ApiResult.ok(token);
    }


    public JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
        String result = "";
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);
        try {
            // 如果密钥不足16位，那么就补足. 这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base
                        + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters
                    .getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                result = new String(resultByte, "UTF-8");
            }
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage(), e);
        } catch (NoSuchPaddingException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidParameterSpecException e) {
            log.error(e.getMessage(), e);
        } catch (IllegalBlockSizeException e) {
            log.error(e.getMessage(), e);
        } catch (BadPaddingException e) {
            log.error(e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidKeyException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidAlgorithmParameterException e) {
            log.error(e.getMessage(), e);
        } catch (NoSuchProviderException e) {
            log.error(e.getMessage(), e);
        }
        JSONObject userInfo = JSON.parseObject(result);
        return userInfo;
    }
}
